[assembly: WebActivator.PostApplicationStartMethod(typeof(DCHealthCheck.MvcWeb.SimpleInjectorInitializer), "Initialize")]

namespace DCHealthCheck.MvcWeb {

    #region Usings
    using DCHealthCheck.DomainModel;
    using DCHealthCheck.MvcWeb.Classes;
    using DCHealthCheck.MvcWeb.Classes.DataServices;
    using DCHealthCheck.MvcWeb.Classes.ViewModels;
    using DCHealthCheck.MvcWeb.Controllers;
    using SimpleInjector;
    using SimpleInjector.Advanced;
    using SimpleInjector.Extensions;
    using SimpleInjector.Integration.Web;
    using SimpleInjector.Integration.Web.Mvc;
    using System;
    using System.Linq;
    using System.Reflection;
    using System.Threading;
    using System.Web;
    using System.Web.Mvc;
    #endregion

    public static class SimpleInjectorInitializer {

        /// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
        public static void Initialize() {

            // Did you know the container can diagnose your configuration? Go to: http://bit.ly/YE8OJj.
            var container = new Container();

            InitializeContainer(container);

            container.RegisterMvcControllers(Assembly.GetExecutingAssembly());

            container.RegisterMvcAttributeFilterProvider();

            container.Verify();

            DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));

        }

        private static void InitializeContainer(Container container) {
            var hybridLifestyle = Lifestyle.CreateHybrid(
                lifestyleSelector: () => HttpContext.Current != null,
                trueLifestyle: new WebRequestLifestyle(),
                falseLifestyle: Lifestyle.Transient);

            // Example of how to enable use of a custom attribute for Property Injection
            //container.Options.AutowirePropertiesWithAttribute<InjectAttribute>();

            container.Register<IEntityManagerFactory, EntityManagerFactory>(hybridLifestyle);
            container.Register<IEntityManager>(() => new EntityManagerFactory().GetInstance(), hybridLifestyle);

            container.Register<IRepository<SystemInfo, IEntityManager>>(() =>
                new Repository<SystemInfo, IEntityManager>(container.GetInstance<IEntityManager>()), hybridLifestyle);
            container.Register<IRepository<DomainController, IEntityManager>>(() =>
                new Repository<DomainController, IEntityManager>(container.GetInstance<IEntityManager>()), hybridLifestyle);
            container.Register<IRepository<GroupPolicySysvolInfo, IEntityManager>>(() =>
                new Repository<GroupPolicySysvolInfo, IEntityManager>(container.GetInstance<IEntityManager>()), hybridLifestyle);
            container.Register<IRepository<HealthCheckSummary, IEntityManager>>(() =>
                new Repository<HealthCheckSummary, IEntityManager>(container.GetInstance<IEntityManager>()), hybridLifestyle);
            container.Register<IRepository<NetstatInfo, IEntityManager>>(() =>
                new Repository<NetstatInfo, IEntityManager>(container.GetInstance<IEntityManager>()), hybridLifestyle);
            container.Register<IRepository<PendingReplication, IEntityManager>>(() =>
                new Repository<PendingReplication, IEntityManager>(container.GetInstance<IEntityManager>()), hybridLifestyle);
            container.Register<IRepository<DCHealthCheck.DomainModel.ProcessInfo, IEntityManager>>(() =>
                new Repository<DCHealthCheck.DomainModel.ProcessInfo, IEntityManager>(container.GetInstance<IEntityManager>()), hybridLifestyle);
            container.Register<IRepository<InstalledProduct, IEntityManager>>(() =>
                new Repository<InstalledProduct, IEntityManager>(container.GetInstance<IEntityManager>()), hybridLifestyle);
            container.Register<IRepository<ReplicationNeighbor, IEntityManager>>(() =>
                new Repository<ReplicationNeighbor, IEntityManager>(container.GetInstance<IEntityManager>()), hybridLifestyle);
            container.Register<IRepository<ServiceInfo, IEntityManager>>(() =>
                new Repository<ServiceInfo, IEntityManager>(container.GetInstance<IEntityManager>()), hybridLifestyle);
            container.Register<IRepository<TimeSyncInfo, IEntityManager>>(() =>
                new Repository<TimeSyncInfo, IEntityManager>(container.GetInstance<IEntityManager>()), hybridLifestyle);

            container.Register<IResultsDataService>(() =>
                new ResultsDataService(
                    container.GetInstance<IRepository<DomainController, IEntityManager>>(),
                    container.GetInstance<IRepository<SystemInfo, IEntityManager>>()),
                hybridLifestyle);
            container.Register<IDCDataService>(() =>
                new DCDataService(
                    container.GetInstance<IRepository<DomainController, IEntityManager>>()),
                hybridLifestyle);
            container.Register<IGroupPolicySysvolInfoDataService>(() =>
                new GroupPolicySysvolInfoDataService(
                    container.GetInstance<IRepository<DomainController, IEntityManager>>(),
                    container.GetInstance<IRepository<GroupPolicySysvolInfo, IEntityManager>>()),
                hybridLifestyle);
            container.Register<IHomeDataService>(() =>
                new HomeDataService(
                    container.GetInstance<IRepository<DomainController, IEntityManager>>(),
                    container.GetInstance<IRepository<HealthCheckSummary, IEntityManager>>()),
                hybridLifestyle);
            container.Register<INetstatInfoDataService>(() =>
                new NetstatInfoDataService(
                    container.GetInstance<IRepository<DomainController, IEntityManager>>(),
                    container.GetInstance<IRepository<NetstatInfo, IEntityManager>>()),
                hybridLifestyle);

            container.Register<IPendingReplicationsDataService>(() =>
                new PendingReplicationsDataService(
                    container.GetInstance<IRepository<DomainController, IEntityManager>>(),
                    container.GetInstance<IRepository<PendingReplication, IEntityManager>>()),
                hybridLifestyle);

            container.Register<IProcessInfoDataService>(() =>
                new ProcessInfoDataService(
                    container.GetInstance<IRepository<DomainController, IEntityManager>>(),
                    container.GetInstance<IRepository<DCHealthCheck.DomainModel.ProcessInfo, IEntityManager>>()),
                hybridLifestyle);

            container.Register<IProductsDataService>(() =>
                new ProductsDataService(
                    container.GetInstance<IRepository<DomainController, IEntityManager>>(),
                    container.GetInstance<IRepository<InstalledProduct, IEntityManager>>()),
                hybridLifestyle);

            container.Register<IReplicationNeighborDataService>(() =>
                new ReplicationNeighborDataService(
                    container.GetInstance<IRepository<DomainController, IEntityManager>>(),
                    container.GetInstance<IRepository<ReplicationNeighbor, IEntityManager>>()),
                hybridLifestyle);

            container.Register<IServiceInfoDataService>(() =>
                new ServiceInfoDataService(
                    container.GetInstance<IRepository<DomainController, IEntityManager>>(),
                    container.GetInstance<IRepository<ServiceInfo, IEntityManager>>()),
                hybridLifestyle);

            container.Register<ITimeSyncInfoDataService>(() =>
                new TimeSyncInfoDataService(
                    container.GetInstance<IRepository<DomainController, IEntityManager>>(),
                    container.GetInstance<IRepository<TimeSyncInfo, IEntityManager>>()),
                hybridLifestyle);

            container.Register<WebErrorInfo>(() => new WebErrorInfoFactory().GetWebErrorInfo(), hybridLifestyle);

            container.RegisterInitializer<IEntityManager>(instance => {
                var disposable = instance as IDisposable;
                SimpleInjectorWebExtensions.RegisterForDisposal(disposable);
            });

            // Example of Property Injection
            //container.RegisterInitializer<ISomeType>(instance => {
            //    instance.SomeProperty = container.GetInstance<IPropertType>();
            //});

        }
    }

    public static class AttributedPropertyInjectionExtensions {

        public static void AutowirePropertiesWithAttribute<TAttribute>(
            this ContainerOptions options)
            where TAttribute : Attribute {
            options.PropertySelectionBehavior =
                new AttributePropertyInjectionBehavior(
                    options.PropertySelectionBehavior,
                    typeof(TAttribute));
        }

        private sealed class AttributePropertyInjectionBehavior
            : IPropertySelectionBehavior {

            private readonly IPropertySelectionBehavior behavior;
            private readonly Type attribute;

            public AttributePropertyInjectionBehavior(
                IPropertySelectionBehavior baseBehavior,
                Type attributeType) {
                this.behavior = baseBehavior;
                this.attribute = attributeType;
            }

            public bool SelectProperty(Type type, PropertyInfo prop) {
                return this.IsPropertyDecorated(prop) ||
                    this.behavior.SelectProperty(type, prop);
            }

            private bool IsPropertyDecorated(PropertyInfo p) {
                return p.GetCustomAttributes(this.attribute, true).Any();
            }
        }
    }
}